#include <iostream>
#include <cstdio>
#include <algorithm>
#include <utility>
#include <vector>
#include <queue>
#include <set>
#include <map>
#include <functional>
#include <iterator>
#include <random>
#include <chrono>
using std::cin;
using std::cout;

#define F(i, l, r) for (auto i = (l); i <= (r); ++i)
#define dF(i, l, r) for (auto i = (l); i >= (r); --i)
#define F2(i, l, r) for (auto i = (l); i < (r); ++i)

void Solve();
int main() {
#ifndef PKRBT
    [[maybe_unused]] auto tmp1_ = std::freopen("detect.in", "r", stdin);
    [[maybe_unused]] auto tmp2_ = std::freopen("detect.out", "w", stdout);
    std::ios::sync_with_stdio(false);
    cin.tie(nullptr);
#endif
    int tests = 1;
    cin >> tests;
    F(t, 1, tests)
        Solve();
    return 0;
}

using LL = long long;

template<typename T>
using Vec = std::vector<T>;

constexpr int Inf = 0x3f3f3f3f;

std::mt19937_64 rng{(unsigned long long)std::chrono::steady_clock().now().time_since_epoch().count()};

void Solve() {
    int n, m, L, V;
    cin >> n >> m >> L >> V;
    struct car_t { int d, v, a; };
    Vec<car_t> cars(n);
    F2(i, 0, n) {
        int d, v, a;
        cin >> d >> v >> a;
        cars[i] = car_t{d, v, a};
    }
    Vec<int> poss(m);
    F2(i, 0, m)
        cin >> poss[i];
    auto lb = [&](int d) -> int {
        return (int)(std::lower_bound(poss.begin(), poss.end(), d) - poss.begin());
    };
    auto ub = [&](int d) -> int {
        return (int)(std::upper_bound(poss.begin(), poss.end(), d) - poss.begin());
    };
    struct interval_t { int lb, rb; };
    Vec<interval_t> intervals;
    auto try_interval = [&](int l, int r = Inf) -> void {
        if (r == Inf)
            r = m - 1;
        if (l > r)
            return ;
        intervals.push_back(interval_t{l, r});
    };
    for (const car_t &car : cars) {
        int d = car.d;
        int v = car.v;
        int a = car.a;
        if (a == 0)
            if (v <= V)
                ; // no_op
            else
                try_interval(lb(d));
        else if (a > 0)
            if (v > V)
                try_interval(lb(d));
            else
                try_interval(ub(d + (V * V - v * v) / (2 * a)));
        else // if (a < 0)
            if (v <= V)
                ; // no_op
            else
                try_interval(lb(d), ub(d + (v * v - V * V - 1) / (2 * -a)) - 1);
    }
    int ans1 = (int)intervals.size();
    std::sort(intervals.begin(), intervals.end(), [](const interval_t &i1, const interval_t &i2) {
        return i1.rb != i2.rb ? i1.rb < i2.rb : i1.lb > i2.lb;
    });
    int ans2 = 0;
    if (!intervals.empty()) {
        ans2 = 1;
        int lstp = 0;
        F2(i, 1, (int)intervals.size())
            if (intervals[i].lb > intervals[lstp].rb) {
                ++ans2;
                lstp = i;
            }
    }
    cout << ans1 << ' ' << (m - ans2) << '\n';
}
